package com.basker.pisces.domain.validation;

import java.util.ArrayList;
import java.util.Collections;
import java.util.LinkedHashSet;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.function.BiPredicate;
import java.util.stream.Collectors;

import org.apache.commons.collections.ListUtils;
import org.springframework.util.Assert;
import org.springframework.util.CollectionUtils;

import com.basker.pisces.domain.validation.meta.Validation;
import com.basker.pisces.service.exception.IObjectErrorsWrapper.ObjectError;

public class ValidationErrorsUtils {

    /**
     * 判断ObjectError是否和validationName匹配
     */
    private static final BiPredicate<IValidationObjectError<?>, String> matchByValidationName = (error,
                                                                                                 validationName) -> {
        Validation validation = error.getValidation();
        return validation != null && validationName.equals(validation.getName());
    };

    /**
     * 判断ObjectError是否和validation类型匹配
     */
    private static final BiPredicate<IValidationObjectError<?>, Class<? extends Validation>> matchByValidationType = (
            error, validationType) -> {
        Validation validation = error.getValidation();
        return validation != null && validationType.isAssignableFrom(validation.getClass());
    };

    /**
     * 从objects过滤出有效的业务对象
     *
     * @param objects
     * @param errorObjects
     * @return
     */
    @SuppressWarnings("unchecked")
    public static List<Object> filterValidObjects(List<Object> objects, List<Object> errorObjects) {
        if (CollectionUtils.isEmpty(objects)) {
            return Collections.emptyList();
        }

        return ListUtils.subtract(objects, errorObjects);
    }

    /**
     * 从errors中查找来源于指定验证器的错误
     *
     * @param objectErrors
     * @param validationType
     * @return
     */
    public static List<ObjectError> findErrorsByValidation(List<IValidationObjectError<?>> objectErrors,
                                                           Class<? extends Validation> validationType) {
        if (CollectionUtils.isEmpty(objectErrors)) {
            return Collections.emptyList();
        }

        Assert.notNull(validationType, "parameter 'validationType' is required");

        return objectErrors.stream().filter(e -> matchByValidationType.test(e, validationType))
                .map(e -> (ObjectError) e).collect(Collectors.toList());
    }

    /**
     * 从errors中查找来源于指定验证器的错误
     *
     * @param objectErrors
     * @param validationName
     * @return
     */
    public static List<ObjectError> findErrorsByValidation(List<IValidationObjectError<?>> objectErrors,
                                                           String validationName) {
        if (CollectionUtils.isEmpty(objectErrors)) {
            return Collections.emptyList();
        }

        Assert.hasText(validationName, "parameter 'validationName' is required");

        return objectErrors.stream().filter(e -> matchByValidationName.test(e, validationName))
                .map(e -> (ObjectError) e).collect(Collectors.toList());
    }

    /**
     * 获取有错误的业务对象
     *
     * @param objectErrors
     * @return
     */
    public static List<Object> getErrorObjects(List<ObjectError> objectErrors) {
        if (CollectionUtils.isEmpty(objectErrors)) {
            return Collections.emptyList();
        }

        return new ArrayList<>(objectErrors.stream().map(e -> e.getObject()).filter(o -> o != null)
                .collect(Collectors.toCollection(() -> new LinkedHashSet<>(objectErrors.size(), 1))));
    }

    /**
     * 获取errorObject的错误
     *
     * @param objectErrors
     * @param errorObject
     * @return
     */
    public static List<ObjectError> getErrors(List<ObjectError> objectErrors, Object errorObject) {
        Assert.notNull(errorObject, "parameter 'errorObject' is required");

        if (CollectionUtils.isEmpty(objectErrors)) {
            return Collections.emptyList();
        }

        return objectErrors.stream().filter(e -> Objects.equals(e.getObject(), errorObject))
                .collect(Collectors.toList());
    }

    /**
     * 按{@link ObjectError#getObject()}对objectErrors进行分组
     *
     * @param objectErrors
     * @return
     */
    public static Map<Object, List<ObjectError>> groupByErrorObject(List<ObjectError> objectErrors) {
        if (CollectionUtils.isEmpty(objectErrors)) {
            return Collections.emptyMap();
        }

        return objectErrors.stream().collect(Collectors.groupingBy(e -> e.getObject()));
    }

    /**
     * 判断errors是否是因为指定验证器而出错
     *
     * @param objectErrors
     * @param validationType
     * @return
     */
    public static boolean isCauseByValidation(List<IValidationObjectError<?>> objectErrors,
                                              Class<? extends Validation> validationType) {
        if (CollectionUtils.isEmpty(objectErrors)) {
            return false;
        }

        Assert.notNull(validationType, "parameter 'validationType' is required");

        return objectErrors.stream().anyMatch(e -> matchByValidationType.test(e, validationType));
    }

    /**
     * 判断errors是否是因为指定验证器而出错
     *
     * @param objectErrors
     * @param validationName
     * @return
     */
    public static boolean isCauseByValidation(List<IValidationObjectError<?>> objectErrors, String validationName) {
        if (CollectionUtils.isEmpty(objectErrors)) {
            return false;
        }

        Assert.hasText(validationName, "parameter 'validationName' is required");

        return objectErrors.stream().anyMatch(e -> matchByValidationName.test(e, validationName));
    }

}
